package com.sky.setmeal.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.category.mapper.CategoryMapper;
import com.sky.constant.MessageConstant;
import com.sky.constant.StatusConstant;
import com.sky.dto.SetmealDTO;
import com.sky.dto.SetmealPageQueryDTO;
import com.sky.entity.Category;
import com.sky.entity.Setmeal;
import com.sky.entity.SetmealDish;
import com.sky.exception.DeletionNotAllowedException;
import com.sky.exception.SetmealDishNullPointException;
import com.sky.exception.SetmealNotFoundException;
import com.sky.result.PageResult;
import com.sky.setmeal.mapper.SetMealMapper;
import com.sky.setmeal.service.SetMealService;
import com.sky.setmealdish.service.SetMealDishService;
import com.sky.vo.SetmealVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 套餐管理 serviceImpl
 */
@Slf4j
@Service
public class SetMealServiceImpl implements SetMealService {

    @Resource
    private SetMealMapper setMealMapper;

    @Resource
    private SetMealDishService setMealDishService;

    @Resource
    private CategoryMapper categoryMapper;



    /**
     * 套餐管理
     *       新增套餐 及 套餐菜品关联数据
     */
    @Override
    @Transactional(rollbackFor= Exception.class, propagation= Propagation.REQUIRED) //开启事务
    public void addSetMealAndSetMealDish(SetmealDTO setmealDTO) {
        AtomicInteger setMealDishCount = new AtomicInteger(0);
        // 1.判断关联表数据是否有值
        if(CollectionUtils.isEmpty(setmealDTO.getSetmealDishes())){
            //没有关联表数据 抛出异常
            throw new SetmealDishNullPointException(MessageConstant.SETMEALDISH_IS_NULL);
        }

        // 2.套餐表存入1条数据 对象拷贝  Aop公共字段填充
        // 2.1 封装数据 对象拷贝
        Setmeal setmeal = JSON.parseObject(JSON.toJSONString(setmealDTO, SerializerFeature.WriteMapNullValue), Setmeal.class);
        setmeal.setStatus(StatusConstant.ENABLE);
        Integer setMealCount = setMealMapper.insertSetmeal(setmeal);

        // 3.套餐菜品关联数据插入 单条或多条
        List<SetmealDish> setmealDishList = setmealDTO.getSetmealDishes();
        // 3.1 套餐菜品关联数据过滤空数据
        setmealDishList = setmealDishList.stream().filter(Objects::nonNull).collect(Collectors.toList());
        // 3.2 绑定套餐id
        setmealDishList.forEach(setmealDish -> setmealDish.setSetmealId(setmeal.getId()));
        // 3.3 遍历 插入
        for (SetmealDish setmealDish : setmealDishList) {
            setMealDishService.saveSetmealDish(setmealDish);
            setMealDishCount.incrementAndGet();
        }
        log.info("新增套餐,影响行数: {},套餐关联菜品,影响行数: {}", setMealCount, setMealDishCount);
    }



    /**
     * 套餐管理
     *        分页条件查询
     * @param setmealPageQueryDTO
     */
    @Override
    public PageResult selectPage(SetmealPageQueryDTO setmealPageQueryDTO) {
        // 1.PageHelper设置分页参数  排序参数
        PageHelper.startPage(setmealPageQueryDTO.getPage(), setmealPageQueryDTO.getPageSize());
        // 2.封装数据为PageHelper的集合对象
        Page<SetmealVO> page = setMealMapper.selectPage(setmealPageQueryDTO);
        // 3.返回
        return new PageResult(page.getTotal(), page.getResult());
    }



    /**
     * 套餐管理
     *        根据ids 删除套餐 及 套餐菜品关联
     *        单个套餐  或  多个套餐
     * @param ids
     */
    @Override
    @Transactional(rollbackFor= Exception.class, propagation= Propagation.REQUIRED)
    public void deleteSetmealAndSetmealDish(List<Long> ids) {
        // 1.先判断是否能够删除套餐 --- 当前套餐是否是起售状态
        List<Setmeal> setmealList = setMealMapper.selectStatusByIds(ids);
        if( !CollectionUtils.isEmpty(setmealList) ){
            String nameStr = setmealList.stream().filter(Objects::nonNull)
                                                 .filter(setmeal -> StringUtils.hasLength(setmeal.getName()))
                                                 .map(Setmeal::getName)
                                                 .collect(Collectors.joining(";"));
            //当前套餐中有起售  抛出异常
            throw new DeletionNotAllowedException(MessageConstant.SETMEAL_ON_SALE + nameStr);
        }
        // 2.删除套餐数据
        Integer setMealCount = setMealMapper.deleteByIds(ids);
        // 3.删除套餐菜品关联数据
        Integer setmealDishCount = setMealDishService.deleteBySetmealIds(ids);
        log.info("当前需要删除套餐有: {}条,套餐数据删除: {}条,套餐菜品关联数据删除: {}条", ids.size(), setMealCount, setmealDishCount);
    }



    /**
     * 套餐管理
     *        根据id查询 套餐及套餐菜品关联
     * @param id
     */
    @Override
    public SetmealVO selectSetmealAndSetmealDish(Long id) {
        // 1.查询套餐 并判断
        Setmeal setmeal = setMealMapper.selectById(id);
        if(Objects.isNull(setmeal)){
            //套餐不存在 抛出异常
            throw new SetmealNotFoundException(MessageConstant.SETMEAL_IS_NULL);
        }
        // 2.对象拷贝 封装数据
        SetmealVO setmealVO = JSON.parseObject(JSON.toJSONString(setmeal, SerializerFeature.WriteMapNullValue), SetmealVO.class);
        // 3.查询分类名称
        Category category = categoryMapper.selectById(setmeal.getCategoryId());
        if(Objects.nonNull(category)) {
            setmealVO.setCategoryName(category.getName());
        }
        // 4.查询套餐菜品关联
        List<SetmealDish> setmealDishList = setMealDishService.selectBySetmealId(id);
        if(CollectionUtils.isEmpty(setmealDishList)){
            //套餐 没有套餐菜品关联数据 抛出异常
            throw new SetmealDishNullPointException(MessageConstant.SETMEALDISH_NOT_FOUND);
        }
        // 5.返回
        setmealVO.setSetmealDishes(setmealDishList);
        return setmealVO;
    }



    /**
     * 套餐管理
     *        修改套餐以及套餐菜品关联数据
     * @param setmealDTO
     */
    @Override
    @Transactional(rollbackFor= Exception.class, propagation= Propagation.REQUIRED)  //开启事务
    public void updateSetmealAndSetmealDish(SetmealDTO setmealDTO) {
        AtomicInteger setMealDishCount = new AtomicInteger(0);
        // 1.修改套餐信息
        // 1.1 对象拷贝 aop公共字段填充值
        Setmeal setmeal = JSON.parseObject(JSON.toJSONString(setmealDTO, SerializerFeature.WriteMapNullValue), Setmeal.class);
        Integer setMealCount = setMealMapper.updateById(setmeal);
        // 2.删除原来套餐关联的菜品
        Integer deleteSetMealDishCount = setMealDishService.deleteBySetmealIds(Collections.singletonList(setmealDTO.getId()));
        // 3.新增套餐关联的菜品
        if( !CollectionUtils.isEmpty(setmealDTO.getSetmealDishes()) ){
            List<SetmealDish> setmealDishList = setmealDTO.getSetmealDishes();
            //给套餐新关联的数据设置套餐id
            setmealDishList.forEach(setmealDish -> setmealDish.setSetmealId(setmealDTO.getId()));
            for (SetmealDish setmealDish : setmealDishList) {
                setMealDishService.saveSetmealDish(setmealDish);
                setMealDishCount.incrementAndGet();
            }
        }
        log.info("修改套餐id: {},影响行数: {},删除原来套餐菜品关联数据: {}条,新增套餐菜品关联数据: {}条", setmealDTO.getId(), setMealCount, deleteSetMealDishCount, setMealDishCount);
    }



    /**
     * 套餐管理
     *        启用、禁用
     * @param id
     * @param status
     */
    @Override
    public void updateStatusById(Long id, Integer status) {
        // 1.封装数据 aop
        Setmeal setmeal = Setmeal.builder().id(id).status(status).build();
        // 2.调用法
        Integer setmealCount = setMealMapper.updateById(setmeal);
        log.info("套餐id: {},启用禁用影响行数: {}", id, setmealCount);
    }



    /**
     * 套餐管理
     *        控制台展示统计的 停售/起售 套餐数量
     * @param map
     */
    @Override
    public Integer countSetmealStatusByMap(Map map) {
        return setMealMapper.countSetmealStatusByMap(map);
    }
}
